#coding:utf-8

from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore

PORT = 5005
NAME = 'TestChat'
class EndSession(Exception):pass

class CommandHandler:
    '''
	A simmple command handler same like cmd.Cmd
	'''
	
	def unknown(self, session, cmd):
		session.push('Unknown command: %s\r\n' %cmd)
		
	def handle(self, session, cmd):
		'处理从给定会话中接收到的行'
		if not line.strip():return
		#分离命令
		parts = line.split(' ',1)
		cmd = parts[0]
		try:line = parts[1].strip()
		except IndexError:line = ''
		meth = getattr(self, 'do_'+cmd, None)
		try:meth(session, line)
		except TypeError:self.unknown(session, cmd)
		
class Room(CommandHandler):
	'''
	可以处理一个或多个用户的泛型环境。负责基本的命令处理和广播
	'''
	def __init__(self, server):
		self.server = server
		self.sessions = []
		
	def add(self, session):
		self.sessions.append(session)
	
	def remove(self, session):
		self.sessions.remove(session)
		
	def broadcast(self, line):
		for session in self.sessions:
			session.push(line)
			
	def do_logout(self, session, line):
		raise EndSession
		
class LoginRoom(Room):
	'''
	为刚连接上的用户准备的房间
	'''
	def add(self, session):
		Room.add(self, session)
		self.broadcast('welcome to %s\r\n' %self.server.name)
		
	def unknown(self, session):
		session.push('Please log in\nUser "login <nick>"\r\n')
		
	def do_login(self,session,line):
		name = line.strip()
		if not name:
			session.push('please enter a name\r\n')
		elif name in self.server.users:
			session.push('The name "%s" is taken.\r\n' %name)
			session.push('Please try again.\r\n')
		else:
			session.name = name
			session.enter(self.server.main_room)
			
class LogoutRoom(Room):
	def add(self, session):
		try: del self.server.users[session.name]
		except KeyError:pass
		
class ChatRoom(Room):
	'''
	多用户聊天的房间
	'''
	def add(self, session):
		self.broadcast(session.name + 'has entered the room.\r\n')
		self.server.users[session.name] = session
		Room.add(self, session)
	
	def remove(self, session):
		Room.remove(self, session)
		self.broadcast(session.name + 'has left the room.\r\n')
	
	def do_say(self, session, line):
		self.broadcast(session.name + ': '+ line+ 'r\n')
		
	def do_look(self, session, line):
		session.push('the following are in this room:\r\n')
		for other in self.sessions:
			session.push(other.name + '\r\n')
			
	def do_who(self, session, line):
		session.push('the following are logged in:\r\n')
		for name in self.server.users:
			session.push(name + '\r\n')
	
class  ChatSession(async_chat):
	'''
	处理服务器和一个用户之间连接的类
	'''
	def __init__(self,server, sock):
		#标准设置任务，初始化
		async_chat.__init__(self, sock)
		self.set_terminiator("\r\n")
		self.data = []
		self.name = None
		self.enter(LoginRoom(server))
		
	def enter(self, room):
		try:cur = self.room
		except AttributeError:pass
		else:cur.remove(self)
		self.room = room
		room.add(self)
		
	def collect_incoming_data(self, data):
		self.data.append(data)
	
	def found_terminiator(self):
		#发现终止对象即发现一个完整行，将其广播给用户
		line = ''.jion(self.data)
		self.data = []
		try:self.room.handle(self.line)
		except EndSession:
			self.handle_close()
		
	def handle_close():
		async_chat.handle_close(self)
		self.enter(LogoutRoom(self.server))
		
class ChatServer(dispatcher):
	'''
	只有一个房间的聊天服务器。
	'''
	def __init__(self, port, name):
		dispatcher.__init__(self)
		self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
		self.set_reuse_addr()          
		self.bind(('',port))
		self.listen(5)
		self.name = name           #绑定名称
		self.users = {}
		self.main_room = ChatRoom(self)
	
	'''
	def disconnect(self, session)       #移除断开用户
		self.sessions.remove(session)
	def broadcast(self, session)       #定义广播
		for session in self.sessions:
			session.push(line+'\r\n')
	'''
	
	def handle_accept(self):                 
		conn, addr = self.accept()
		ChatSession(self, conn)  

if __name__== '__main__':
	s = ChatServer(PORT, NAME)
	try:asyncore.loop()
	except KeyboardInterrupt:pass